package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.minio.service.FileOpsService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;
    @Autowired
    private VodService vodService;
    @Autowired
    private TrackStatMapper trackStatMapper;
    @Autowired
    private AlbumInfoMapper albumInfoMapper;
    @Autowired
    private FileOpsService fileOpsServiceImpl;
    @Autowired
    @Qualifier("com.atguigu.tingshu.user.client.UserInfoFeignClient")
    private UserInfoFeignClient userInfoFeignClient;

    @Override
    public Map<String, Object> uploadTrack(MultipartFile file) {
        return vodService.uploadTrack(file);
    }

    @Override
    public IPage<TrackListVo> findUserTrackPage(IPage<TrackListVo> trackListVoPage, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.findUserTrackPage(trackListVoPage, trackInfoQuery);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveTrackInfo(TrackInfoVo trackInfoVo) {
        TrackInfoServiceImpl proxy = (TrackInfoServiceImpl) AopContext.currentProxy();

        // 保存声音信息
        Long userId = AuthContextHolder.getUserId();
        TrackInfo trackInfo = new TrackInfo();
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        trackInfo.setUserId(userId);
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
        //设置trackInfo序列号
        LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<TrackInfo>()
                .eq(TrackInfo::getAlbumId, trackInfoVo.getAlbumId())
                .select(TrackInfo::getOrderNum)
                .orderByDesc(TrackInfo::getOrderNum)
                .last("limit 1");
        TrackInfo maxOrderNumTrackInfo = trackInfoMapper.selectOne(wrapper);
        trackInfo.setOrderNum(maxOrderNumTrackInfo != null ? maxOrderNumTrackInfo.getOrderNum() + 1 : 1);
        TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());
        if (trackMediaInfoVo != null) {
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfoVo.getDuration()));
            trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
        }
        trackInfoMapper.insert(trackInfo);
        // 保存声音的统计信息
        proxy.initTrackStat(trackInfo.getId());
        //修改这个声音对应专辑的包含声音级数
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        if (albumInfo != null) {
            albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        }
        albumInfoMapper.updateById(albumInfo);
    }

    // 查询声音信息
    @Override
    public TrackInfo getTrackInfo(Long trackId) {
        return trackInfoMapper.selectById(trackId);
    }

    // 修改声音信息
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) {
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        if (trackInfo == null) {
            throw new GuiguException(201, "声音不存在");
        }

        //判断是否修改图片
        String coverUrl = trackInfoVo.getCoverUrl();
        if (StringUtils.hasText(coverUrl)) {
            String trackInfoCoverUrl = trackInfo.getCoverUrl();
            String originalFilename = trackInfoCoverUrl.substring(trackInfoCoverUrl.lastIndexOf("/"), trackInfoCoverUrl.length());
            fileOpsServiceImpl.minioDeleteExample(originalFilename);
        }

        String oldMediaFileId = trackInfo.getMediaFileId();
        String newMediaFileId = trackInfoVo.getMediaFileId();
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        if (StringUtils.hasText(newMediaFileId) && !newMediaFileId.equals(oldMediaFileId)) {
            TrackMediaInfoVo mediaInfo = vodService.getMediaInfo(newMediaFileId);
            trackInfo.setMediaSize(mediaInfo.getSize());
            trackInfo.setMediaDuration(BigDecimal.valueOf(mediaInfo.getDuration()));
            trackInfo.setMediaUrl(mediaInfo.getMediaUrl());
            trackInfo.setMediaType(mediaInfo.getType());
        }
        trackInfoMapper.updateById(trackInfo);
    }

    // 删除声音信息
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeTrackInfo(Long trackId) {
        TrackInfoServiceImpl proxy = (TrackInfoServiceImpl) AopContext.currentProxy();
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);

        String coverUrl = trackInfo.getCoverUrl();
        String originalFilename = coverUrl.substring(coverUrl.lastIndexOf("/"), coverUrl.length());
        fileOpsServiceImpl.minioDeleteExample(originalFilename);

        trackInfoMapper.deleteById(trackId);

        LambdaQueryWrapper<TrackStat> queryWrapper = new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, trackId);
        trackStatMapper.delete(queryWrapper);

        Long albumId = trackInfo.getAlbumId();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        albumInfoMapper.updateById(albumInfo);

        LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<TrackInfo>()
                .gt(TrackInfo::getOrderNum, trackInfo.getOrderNum())
                .eq(TrackInfo::getAlbumId, albumId);
        List<TrackInfo> trackInfoList = trackInfoMapper.selectList(wrapper);
        if (!CollectionUtils.isEmpty(trackInfoList)) {
            List<TrackInfo> trackInfos = trackInfoList.stream().map(trackInfo1 -> {
                trackInfo1.setOrderNum(trackInfo1.getOrderNum() - 1);
                return trackInfo1;
            }).collect(Collectors.toList());
            proxy.updateBatchById(trackInfos);
        }
        //todo 删除Vod声音资源
        vodService.removeVodMedia(trackInfo.getMediaFileId());

    }

    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(IPage<AlbumTrackListVo> albumTrackListVo, Long albumId) {
        IPage<AlbumTrackListVo> result = new Page<>();
        // 查询分页数据(目前所有声音都是免费 isShowPaidMark = false)
        IPage<AlbumTrackListVo> albumTrackPage = trackInfoMapper.findAlbumTrackPage(albumTrackListVo, albumId);
        // 查询专辑信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new GuiguException(201, "专辑不存在");
        }
        // 判断专辑是否是付费的
        String payType = albumInfo.getPayType();
        String priceType = albumInfo.getPriceType();
        Integer tracksForFree = albumInfo.getTracksForFree();
        Long userId = AuthContextHolder.getUserId();
        switch (payType) {
            //0101:免费 0102:Vip免费 0103:付费
            case "0101":
                result = albumTrackPage;
                break;
            case "0102":
                result = dealPayTypeVip(albumId, priceType, tracksForFree, userId, albumTrackPage);
                break;
            case "0103":
                result = dealPayTypeNeedPaid(albumId, priceType, tracksForFree, userId, albumTrackPage);

        }
        return result;
    }

    @Override
    public TrackStatVo getTrackStatVo(Long trackId) {
        return trackStatMapper.getTrackStatVo(trackId);
    }

    @Override
    public List<TrackListVo> getTrackInfoList(List<Long> collectTrackIdList) {
        List<TrackInfo> trackInfoList = trackInfoMapper.selectBatchIds(collectTrackIdList);
        return trackInfoList.stream().map(trackInfo -> {
            TrackListVo trackListVo = new TrackListVo();
            BeanUtils.copyProperties(trackInfo, trackListVo);
            trackListVo.setTrackId(trackInfo.getId());
            return trackListVo;
        }).collect(Collectors.toList());
    }

    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long currentTrackId) {
        // 展示当前声音之后的某些集声音
        ArrayList<Map<String, Object>> result = new ArrayList<>();
        // 获取当前声音
        TrackInfo trackInfo = trackInfoMapper.selectById(currentTrackId);
        if (trackInfo == null) {
            throw new GuiguException(201, "声音不存在");
        }
        Integer orderNum = trackInfo.getOrderNum();
        Long albumId = trackInfo.getAlbumId();
        // 获取专辑信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new GuiguException(201, "专辑不存在");
        }
        BigDecimal price = albumInfo.getPrice();
        Long userId = AuthContextHolder.getUserId();
        // 获取当前声音序列号后的声音
        LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<TrackInfo>()
                .eq(TrackInfo::getAlbumId, albumId)
                .ge(TrackInfo::getOrderNum, orderNum)
                .orderByAsc(TrackInfo::getOrderNum)
                .last("limit 50");
        List<TrackInfo> trackInfoList = trackInfoMapper.selectList(wrapper);
        //查询用户已经购买的声音
        Result<Map<Long, String>> userPaidAlbumTrackListResult = userInfoFeignClient.getUserPaidAlbumTrackList(albumId, userId);
        Map<Long, String> userPaidAlbumTrackData = userPaidAlbumTrackListResult.getData();
        Assert.notNull(userPaidAlbumTrackData, "远程调用用户微服务获取用户购买声音信息失败");
        //过滤出没有购买的声音
        List<Long> reallyCanShowTrackLists = trackInfoList.stream()
                .map(TrackInfo::getId)
                .filter(trackId -> !StringUtils.hasText(userPaidAlbumTrackData.get(trackInfo.getId())))
                .collect(Collectors.toList());
        // 展示购买的声音列表
        // 20集声音：3块（本集、后10集、后20集）
        // 23集声音：4块（本集、后10集、后20集 后23集）
        //没有购买的声音集数
        int size = reallyCanShowTrackLists.size();
        //先展示本集
        Map<String, Object> map = new HashMap<>();
        map.put("name", "本集"); // 名字展示
        map.put("price", price);// 本集的价格展示
        map.put("trackCount", 0);// 集数不展示（买本集还是其他集最区分）
        result.add(map);
        //展示集数
        // 20集声音：2块（后10集、后20集）
        // 23集声音：3块（后10集、后20集 后23集）
        // 获取要展示的块数
        //10集                                                                                                  ，，，， ，
        int block = size % 10 == 0 ? size / 10 : size / 10 + 1;
        for (int i = 1; i <= block; i++) {
            int count = i * 10;
            if (count >= size) {
//                Map<String, Object> map2 = new HashMap<>();
//                map2.put("name", "后"+ size +"集"); // 名字展示
//                map2.put("price", price.multiply(new BigDecimal(size)) );// 本集的价格展示
//                map2.put("trackCount", size);
//                result.add(map2);
//                break;
                count = size;
            }
            Map<String, Object> map1 = new HashMap<>();
            map1.put("name", "后" + count + "集"); // 名字展示
            map1.put("price", price.multiply(new BigDecimal(count)));// 本集的价格展示
            map1.put("trackCount", count);
            result.add(map1);
        }
        return result;
    }

    @Override
    public TrackInfo getTrackInfoById(Long trackId) {
        return trackInfoMapper.selectById(trackId);
    }

    @Override
    public Result<List<TrackInfo>> getPaidTrackAndFilterCanPayTrack(Long albumId, Long userId, Integer trackCount, Long trackId) {
        List<TrackInfo> trackInfos = new ArrayList<>();
        // 查询当前用户买过的专辑下的声音
        Result<Map<Long, String>> userPaidAlbumTrackListResult = userInfoFeignClient.getUserPaidAlbumTrackList(albumId, userId);
        Map<Long, String> albumTrackListResultData = userPaidAlbumTrackListResult.getData();
        Assert.notNull(albumTrackListResultData, "远程调用用户微服务获取用户购买声音信息失败");
        // 查询要买的声音
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        if (trackCount == 0) {
            // 购买本集
            trackInfos.add(trackInfo);
        }else {
            LambdaQueryWrapper<TrackInfo> wrapper = new LambdaQueryWrapper<TrackInfo>()
                    .eq(TrackInfo::getAlbumId, albumId)
                    .ge(TrackInfo::getOrderNum, trackInfo.getOrderNum())
                    .last("limit " + trackCount)
                    .orderByAsc(TrackInfo::getOrderNum);
            trackInfos = trackInfoMapper.selectList(wrapper);
        }
        //进行完整的过滤（将已经买过的返回给order--->前端）
        List<TrackInfo> longs = new ArrayList<>();
        for (TrackInfo info : trackInfos) {
            if (StringUtils.hasText(albumTrackListResultData.get(info.getId()))){
                longs.add(info);
                return Result.build(longs,400, "请勿重复购买声音");
            }
        }
        return Result.ok(trackInfos);
    }

    /**
     * 处理付费类型为VIP的逻辑
     *
     * @param albumId        专辑id
     * @param priceType      价格类型
     * @param tracksForFree  专辑免费声音数
     * @param userId         用户id
     * @param albumTrackPage 专辑声音分页数据
     * @return IPage<AlbumTrackListVo>
     */
    private IPage<AlbumTrackListVo> dealPayTypeVip(Long albumId, String priceType, Integer tracksForFree, Long userId, IPage<AlbumTrackListVo> albumTrackPage) {
        if (userId == null) {
            List<AlbumTrackListVo> albumTrackListVoList = albumTrackPage.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() <= tracksForFree).collect(Collectors.toList());
            return albumTrackPage.setRecords(albumTrackListVoList);
        }
        Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfo(userId);
        UserInfoVo userInfoVo = userInfoVoResult.getData();
        if (userInfoVo == null) {
            throw new GuiguException(201, "远程获取用户信息失败");
        }
        Integer isVip = userInfoVo.getIsVip();
        Date vipExpireTime = userInfoVo.getVipExpireTime();
        // 判断用户是否是VIP，并且VIP是否过期
        if ("0".equals(isVip.toString()) || "1".equals(isVip.toString()) && vipExpireTime.before(new Date())) {
            return getReallyAlbumTrackListVoIPage(albumId, priceType, tracksForFree, userId, albumTrackPage);
        } else {
            return albumTrackPage;
        }
    }


    /**
     * 处理付费类型为需要付费的逻辑
     *
     * @param albumId        专辑id
     * @param priceType      价格类型
     * @param tracksForFree  专辑免费声音数
     * @param userId         用户id
     * @param albumTrackPage 专辑声音分页数据
     * @return IPage<AlbumTrackListVo>
     */
    private IPage<AlbumTrackListVo> dealPayTypeNeedPaid(Long albumId, String priceType, Integer tracksForFree, Long userId, IPage<AlbumTrackListVo> albumTrackPage) {
        if (userId == null) {
            List<AlbumTrackListVo> albumTrackListVoList = albumTrackPage.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() <= tracksForFree).collect(Collectors.toList());
            return albumTrackPage.setRecords(albumTrackListVoList);
        }
        return getReallyAlbumTrackListVoIPage(albumId, priceType, tracksForFree, userId, albumTrackPage);
    }

    private IPage<AlbumTrackListVo> getReallyAlbumTrackListVoIPage(Long albumId, String priceType, Integer tracksForFree, Long userId, IPage<AlbumTrackListVo> albumTrackPage) {
        Result<Map<Long, String>> userPaidAlbumTrackListResult = userInfoFeignClient.getUserPaidAlbumTrackList(albumId, userId);
        if ("0201".equals(priceType)) {
            Map<Long, String> userPaidAlbumTrackListMap = userPaidAlbumTrackListResult.getData();
            Assert.notNull(userPaidAlbumTrackListMap, "远程调用获取用户购买专辑声音失败");
            List<AlbumTrackListVo> albumTrackListVoList = albumTrackPage.getRecords().stream().map(albumTrackListVo -> {
                        if (!StringUtils.hasText(userPaidAlbumTrackListMap.get(albumTrackListVo.getTrackId())) && albumTrackListVo.getOrderNum() > tracksForFree) {
                            albumTrackListVo.setIsShowPaidMark(true);
                        }
                        return albumTrackListVo;
                    }
            ).collect(Collectors.toList());
            return albumTrackPage.setRecords(albumTrackListVoList);
        } else {
            Result<Boolean> userPaidAlbumResult = userInfoFeignClient.getUserPaidAlbum(userId, albumId);
            Boolean isPaidAlbum = userPaidAlbumResult.getData();
            Assert.notNull(isPaidAlbum, "远程调用获取用户是否购买专辑失败");
            if (isPaidAlbum) {
                return albumTrackPage;
            } else {
                List<AlbumTrackListVo> collect = albumTrackPage.getRecords().stream().map(albumTrackListVo -> {
                    if (albumTrackListVo.getOrderNum() > tracksForFree) {
                        albumTrackListVo.setIsShowPaidMark(true);
                    }
                    return albumTrackListVo;
                }).collect(Collectors.toList());
                return albumTrackPage.setRecords(collect);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void initTrackStat(Long id) {
        Arrays.asList(SystemConstant.TRACK_STAT_PLAY,
                SystemConstant.TRACK_STAT_COLLECT,
                SystemConstant.TRACK_STAT_PRAISE,
                SystemConstant.TRACK_STAT_COMMENT).forEach(trackStatFrom -> {
            TrackStat trackStat = new TrackStat();
            trackStat.setStatNum(0);
            trackStat.setTrackId(id);
            trackStat.setStatType(trackStatFrom);
            trackStatMapper.insert(trackStat);
        });
    }
}
